package ycl.gateway.exception;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.reactive.function.server.*;
import ycl.common.exception.CustomException;
import ycl.common.result.REnum;
import ycl.common.result.Result;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Order(-1)
public class ExceptionHandler extends DefaultErrorWebExceptionHandler {


	/**
	 * Create a new {@code DefaultErrorWebExceptionHandler} instance.
	 *
	 * @param errorAttributes    the error attributes
	 * @param resourceProperties the resources configuration properties
	 * @param errorProperties    the error configuration properties
	 * @param applicationContext the current application context
	 */
	public ExceptionHandler(ErrorAttributes errorAttributes,
							ResourceProperties resourceProperties,
							ErrorProperties errorProperties,
							ApplicationContext applicationContext) {
		super(errorAttributes, resourceProperties, errorProperties, applicationContext);
	}

	@Override
	protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
		Result<Object> result = getException(request);
		JSONObject json = JSONObject.parseObject(result.toString());
		return new HashMap<>(json);
	}

	private Result<Object> getException(ServerRequest request) {
		Throwable e = getError(request);
		if (e instanceof IllegalArgumentException)
			return Result.fail(e.getMessage());
		if (e instanceof CustomException)
			return Result.fail(((CustomException) e).getEnums());
		if (e instanceof NotFoundException)
			return Result.fail(REnum.USED_NOT_FOUND);
		if (e instanceof JSONException)
			Result.fail("调用者传参异常");
		if (e instanceof MethodArgumentNotValidException)
			return Result.fail(((BindingResult) e).getFieldErrors().get(0).getDefaultMessage());
		log.error(e.getMessage(), e);
		return Result.fail();
	}

	@Override
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
	}

	@Override
	protected int getHttpStatus(Map<String, Object> errorAttributes) {
		return HttpStatus.OK.value();
	}
}
